<?php

declare(strict_types=1);

namespace app\utils;

use Exception;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\SignatureInvalidException;
use app\enum\errcode\ErrCodeEnum;
use Dsxwk\Framework\Utils\Exception\CodeException;

class JwtUtil
{
    /**
     * JWT密钥
     */
    private const SECRET_KEY = 'a123456789';

    /**
     * 访问token过期时间（秒）
     */
    private const ACCESS_TOKEN_EXPIRE = 7200; // 2小时

    /**
     * 刷新token过期时间（秒）
     */
    private const REFRESH_TOKEN_EXPIRE = 604800; // 7天

    /**
     * 生成访问token
     *
     * @param array $payload
     *
     * @return array
     */
    public static function generateAccessToken(array $payload): array
    {
        $payload['exp']  = time() + self::ACCESS_TOKEN_EXPIRE;
        $payload['iat']  = time();
        $payload['type'] = 'access';

        return [
            'token'  => JWT::encode($payload, self::SECRET_KEY, 'HS256'),
            'expire' => $payload['exp'],
        ];
    }

    /**
     * 生成刷新token
     *
     * @param array $payload
     *
     * @return array
     */
    public static function generateRefreshToken(array $payload): array
    {
        $payload['exp']  = time() + self::REFRESH_TOKEN_EXPIRE;
        $payload['iat']  = time();
        $payload['type'] = 'refresh';

        return [
            'token'  => JWT::encode($payload, self::SECRET_KEY, 'HS256'),
            'expire' => $payload['exp'],
        ];
    }

    /**
     * 验证token
     *
     * @param string $token
     *
     * @return array
     * @throws CodeException
     */
    public static function verifyToken(string $token): array
    {
        try {
            $decoded = JWT::decode($token, new Key(self::SECRET_KEY, 'HS256'));

            return (array)$decoded;
        } catch (ExpiredException $e) {
            throwError(ErrCodeEnum::UNAUTHORIZED, 'Token已过期');
        } catch (SignatureInvalidException $e) {
            throwError(ErrCodeEnum::UNAUTHORIZED, 'Token无效');
        } catch (Exception $e) {
            throwError(ErrCodeEnum::UNAUTHORIZED, 'Token验证失败');
        }
    }

    /**
     * 处理token
     *
     * @param string $token
     * @param string $prefix
     *
     * @return false|string
     */
    public static function handleToken(string $token, string $prefix = 'Bearer'): bool|string
    {
        if (strlen($token) > 0) {
            $token = ucfirst($token);
            $arr   = explode("{$prefix} ", $token);
            $token = $arr[1] ?? '';
            if (strlen($token) > 0) {
                return $token;
            }
        }

        return false;
    }

    /**
     * 验证访问token
     *
     * @param string $token
     *
     * @return array
     * @throws CodeException
     */
    public static function verifyAccessToken(string $token): array
    {
        $payload = self::verifyToken($token);

        if ($payload['type'] !== 'access') {
            throwError(ErrCodeEnum::UNAUTHORIZED, '非访问token');
        }

        return $payload;
    }

    /**
     * 验证刷新token
     *
     * @param string $token
     *
     * @return array
     * @throws CodeException
     */
    public static function verifyRefreshToken(string $token): array
    {
        $payload = self::verifyToken($token);

        if ($payload['type'] !== 'refresh') {
            throwError(ErrCodeEnum::UNAUTHORIZED, '非刷新token');
        }

        return $payload;
    }

    /**
     * 从token中获取用户ID
     *
     * @param string $token
     *
     * @return int
     * @throws CodeException
     */
    public static function getUserId(string $token): int
    {
        $payload = self::verifyAccessToken($token);

        return $payload['id'] ?? 0;
    }
}
